package com.zhaojun.cloud.common.util;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ClassUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;

public abstract class FileUtil {

	private static transient Logger logger = LoggerFactory.getLogger(FileUtil.class);

	public  final static String pictureSuffix = "jpg|png|gif|bmp|jpeg";

	/**
	 *  是否是图片文件
	 */
	public static Boolean isPictureSuffix(String suffix){
		String suffixs[] =  StringUtil.split(pictureSuffix,"|");
		if(ArrayUtil.contains(suffixs,suffix.toLowerCase())){
			return true;
		}
		return false;
	}


	public static String safeWindowsFileName(String fileName) {
		if (null != fileName) {
			return fileName.replaceAll("[\\/:*?\"<>|]", "");
		}
		return null;
	}

	public static String readClassPathResourceToString(Class<?> classPackageAsResourcePath, String fileName) {
		String path = ClassUtils.classPackageAsResourcePath(classPackageAsResourcePath) + '/' + fileName;
		return readClassPathResourceToString(path);
	}

	/**
	 * 
	 * @param path
	 * @return
	 */
	public static String readClassPathResourceToString(String path) {

		ClassPathResource classPathResource = null;
		InputStream inputStream = null;

		try {
			classPathResource = new ClassPathResource(path);
			inputStream = classPathResource.getInputStream();
			// 读取不了文件中的中文内容，所以修改 begin
			// return IOUtils.readStringFromStream(inputStream);
			return IoUtil.readStringFromStream(inputStream);
			// 读取不了文件中的中文内容，所以修改 end
		} catch (Exception e) {
			logger.error("error", e);
		} finally {
			IOUtils.closeQuietly(inputStream);
			inputStream = null;
			if (null != classPathResource) {
				classPathResource.exists();
			}
		}
		return null;
	}

	public static void removeAllFilesUnderDirectory(String dir) {
		File fileDir = new File(dir);
		if (fileDir.exists() && fileDir.isDirectory()) {
			File[] files = fileDir.listFiles();
			if (files != null) {
				for (File file : files) {
					file.delete();
				}
			}
		}
	}

	public static void deleteFile(String fileName) {
		File file = new File(fileName);
		if (file.exists() && file.isFile()) {
			file.delete();
		}
	}

	/**
	 * 删除N天以前的数据
	 * 
	 * @param fileName
	 */
	public static void deleteNDayAgoFile(String fileName, int n) {
		File file = new File(fileName);
		int days = (int) ((Calendar.getInstance().getTimeInMillis() - file.lastModified()) / 1000 / 60 / 60 / 24);
		if (days > n) {
			if (file.exists() && file.isFile()) {
				file.delete();
			}
		}
	}

	public static ByteArrayOutputStream getByteArrayOutputStream(String filePath) {
		File file = new File(filePath);
		FileInputStream in = null;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		try {
			in = new FileInputStream(file);
			byte[] buffer = new byte[in.available()];
			in.read(buffer);
			out.write(buffer);
		} catch (Exception e) {
			logger.error("error", e);
		} finally {
			IOUtils.closeQuietly(in);
			in = null;
		}
		return out;
	}

	public static String getChineseFileName(String fileName) {
		String fileEncoding = System.getProperty("file.encoding");
		fileEncoding = fileEncoding != null ? fileEncoding.toUpperCase() : null;
		if (EncodingUtil.ENCODING_UTF8.equals(fileEncoding)) {
			return fileName; // UTF-8，直接返回
		}
		if (EncodingUtil.isWindowsPlatform()) {
			return fileName; // Windows，直接返回
		}
		try {
			if (EncodingUtil.isSimplfiedChineseEncoding(fileEncoding)) {
				// Unix/Linux，并且是中文字符集，直接返回
				return fileName;
			} else {
				// Unix/Linux，并且不是中文字符集，需要转换
				// 参考 http://www.iteye.com/problems/80104
				// Unix上如果系统的file.encoding=UTF-8时，需要在JVM里设置-Dfile.encoding=ISO8859-1，否则还是有乱码问题
				return new String(fileName.getBytes(EncodingUtil.ENCODING_GBK), EncodingUtil.ENCODING_ISO8859_1);
			}
		} catch (UnsupportedEncodingException e) {
			return fileName;
		}
	}

	public static boolean move(String oldFilePathName, String newDirName) {
		File oldFile = new File(oldFilePathName);
		if (!oldFile.exists()) {
			return false;
		}
		File newDir = new File(newDirName);
		if (!newDir.exists()) {
			newDir.mkdirs();
		}
		File newFile = new File(newDirName + File.separator + oldFile.getName());
		return oldFile.renameTo(newFile);
	}

	public static void moveAllFiles(String oldDirName, String newDirName) {
		File newDir = new File(newDirName);
		if (!newDir.exists()) {
			newDir.mkdirs();
		}

		File oldDir = new File(oldDirName);
		File[] fileArray = oldDir.listFiles();
		if (null != fileArray) {
			for (int i = 0; i < fileArray.length; i++) {
				File oldFile = fileArray[i];
				File newFile = new File(newDirName + "/" + oldFile.getName());
				if (!newFile.exists()) {
					oldFile.renameTo(newFile);
				}
			}
		}
	}

	/**
	 * 把文件或文件夹重命名
	 * 
	 * @param filePathName
	 * @param newFileName
	 */
	public static File rename(String filePathName, String newName) {
		File f = new File(filePathName);
		File newFile = null;
		if (f.exists()) {
			String path = filePathName.substring(0, filePathName.lastIndexOf(File.separator));
			newFile = new File(path + File.separator + newName);
			if (!newFile.exists()) {
				if (f.renameTo(newFile)) {
					return newFile;
				}
			}
		}
		return null;
	}

	public static List<File> list(String dirName) {
		File dir = new File(dirName);
		File[] fileArray = dir.listFiles();
		if (null != fileArray) {
			return Arrays.asList(fileArray);
		} else {
			return new ArrayList<File>();
		}
	}

	/**
	 * 把文本文件切割为多个文件
	 * 
	 * @param file
	 * @param fileEncoding
	 *            文件编码
	 * @param splitSize
	 *            分割后每个文件大小，单位为字节
	 * @param headCount
	 *            分割后的每个文件要保留的文件头行数
	 * @return
	 */
	public static List<File> splitTxtFile(File file, String fileEncoding, int splitSize, int headCount) {
		String[] heads = FileUtil.head(file, fileEncoding, headCount);

		List<File> files = new ArrayList<File>();
		BufferedReader br = null;
		BufferedWriter bw = null;
		try {
			if (file.length() <= splitSize) {
				files.add(file);
				return files;
			}
			br = new BufferedReader(new InputStreamReader(new FileInputStream(file), fileEncoding));
			String line = null;
			int byteCount = 0;
			int fileIndex = 1;

			String subFileFullName = file.getAbsolutePath() + ".";
			File subFile = new File(subFileFullName + fileIndex);
			bw = new BufferedWriter(new FileWriter(subFile));

			while (null != (line = br.readLine())) {
				byteCount += line.getBytes().length;
				if (byteCount > splitSize) {
					bw.close();
					bw = null;
					files.add(subFile);

					byteCount = 0;
					fileIndex++;
					subFile = new File(subFileFullName + fileIndex);
					bw = new BufferedWriter(new FileWriter(subFile));
					// 添加文件头
					if (null != heads) {
						for (int i = 0; i < heads.length; i++) {
							String str = heads[i];
							byteCount += str.getBytes().length;
							bw.write(str + "\r\n");
						}
					}
				}
				bw.write(line + "\r\n");
			}

			files.add(subFile);
		} catch (Exception e) {
			logger.error("error", e);
			return null;
		} finally {
			IOUtils.closeQuietly(br);
			br = null;
			IOUtils.closeQuietly(bw);
			bw = null;
		}
		file.delete();
		return files;
	}

	/**
	 * 提取文件的地start行开始，剩下的如果大于nums行，则取nums行，如果不够nums行，则取到end
	 * 
	 * @param file
	 * @param fileEncoding
	 * @param
	 * @return
	 */
	public static String[] fixedLinesRead(File file, String fileEncoding, int start, int nums) {
		int localstart = start - 1;// start 是人的概念，第一行，程序的第一行概念是第0行
		int localend = localstart + nums - 1;
		BufferedReader br = null;
		List<String> strs = new ArrayList<String>();
		try {
			br = new BufferedReader(new InputStreamReader(new FileInputStream(file), fileEncoding));
			String line = null;
			int count = 0;
			while ((count <= localend) && (null != (line = br.readLine()))) {
				if (count >= localstart && line.trim() != "" && line != null && line.length() != 0) {
					strs.add(line);
				}
				count++;
			}
		} catch (IOException e) {
			logger.error("error", e);
		} finally {
			IOUtils.closeQuietly(br);
			br = null;
		}
		logger.info("fileUTil:programming start->" + localstart + ";logical start:" + start + "||||end->" + localend + ";--->total read size:" + strs.size());
		String[] ret = new String[strs.size()];
		return strs.toArray(ret);
	}

	/**
	 * 提取文件的前max行
	 * 
	 * @param file
	 * @param fileEncoding
	 * @param max
	 * @return
	 */
	public static String[] head(File file, String fileEncoding, int max) {
		BufferedReader br = null;
		List<String> strs = new ArrayList<String>();
		try {
			br = new BufferedReader(new InputStreamReader(new FileInputStream(file), fileEncoding));
			String line = null;
			int count = 0;
			while ((count < max) && (null != (line = br.readLine()))) {
				strs.add(line);
				count++;
			}
		} catch (IOException e) {
			logger.error("error", e);
		} finally {
			IOUtils.closeQuietly(br);
			br = null;
		}
		String[] ret = new String[strs.size()];
		return strs.toArray(ret);
	}

	public static String readFileAsString(File file) {
		byte[] bytes = readFileAsBytes(file);
		return new String(bytes);
	}

	public static String readFileAsString(File file, String encoding) {
		byte[] bytes = readFileAsBytes(file);
		try {
			return new String(bytes, encoding);
		} catch (UnsupportedEncodingException e) {
			return "不支持的编码类型" + encoding;
		}
	}

	public static byte[] readFileAsBytes(File file) {
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(file);
			int length = fis.available();
			byte[] bytes = new byte[length];
			fis.read(bytes);
			return bytes;
		} catch (IOException e) {
			logger.error("error", e);
		} finally {
			IOUtils.closeQuietly(fis);
			fis = null;
		}
		return new byte[0];
	}

	public static void save(String content, File file) throws IOException {
		byte[] bytes = content.getBytes();
		save(bytes, file);
	}

	public static void save(byte[] content, File file) throws IOException {
		BufferedOutputStream bos = null;
		BufferedInputStream bis = null;

		try {
			bos = new BufferedOutputStream(new FileOutputStream(file));
			bis = new BufferedInputStream(new ByteArrayInputStream(content));
			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = bis.read(buffer)) != -1) {
				bos.write(buffer, 0, len);
			}
		} catch (Exception e) {
			logger.error("error", e);
		} finally {
			IOUtils.closeQuietly(bos);
			bos = null;
			IOUtils.closeQuietly(bis);
			bis = null;
		}
	}

	public static void save(ByteArrayInputStream bais, File file) throws IOException {
		BufferedOutputStream bos = null;
		BufferedInputStream bis = null;

		try {
			bos = new BufferedOutputStream(new FileOutputStream(file));
			bis = new BufferedInputStream(bais);
			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = bis.read(buffer)) != -1) {
				bos.write(buffer, 0, len);
			}
		} finally {
			IOUtils.closeQuietly(bos);
			bos = null;
			IOUtils.closeQuietly(bis);
			bis = null;
		}
	}

	public static void cleanDir(File dir) {
		if (!dir.exists()) {
			dir.mkdirs();
			return;
		}
		if (!dir.isDirectory()) {
			return;
		}
		if (!dir.canWrite()) {
			return;
		}
		File[] files = dir.listFiles();
		if (null != files) {
			for (int i = 0; i < files.length; i++) {
				File file = files[i];
				if (file.isFile()) {
					file.delete();
				} else {
					cleanDir(file);
				}
			}
		}
	}

	public static BufferedWriter openTxtFileForWrite(File f) {
		return openTxtFileForWrite(f, "GBK");
	}

	public static BufferedWriter openTxtFileForWrite(File f, String encoding) {
		return openTxtFileForWrite(f, encoding, false);
	}

	public static BufferedWriter openTxtFileForWrite(File f, String encoding, boolean withBOM) {
		if (null == f) {
			return null;
		}
		if (f.exists()) {
			f.delete();
		}
		try {
			f.createNewFile();
		} catch (IOException e) {
			logger.error("error", e);
			return null;
		}
		BufferedWriter bw = null;
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(f);
			if (withBOM && "UTF-8".equalsIgnoreCase(encoding)) {
				fos.write(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF });
			}
			bw = new BufferedWriter(new OutputStreamWriter(fos, encoding));
		} catch (IOException e) {
			logger.error("error", e);
			return null;
		} finally {
			IOUtils.closeQuietly(fos);
			fos = null;
		}
		return bw;
	}

	public static void closeFileWriter(Writer writer) {
		IOUtils.closeQuietly(writer);
	}

	public static boolean mkdir(String dirPath) throws IOException {
		boolean ret = false;
		File f = new File(dirPath);
		if (!f.exists()) {
			ret = f.mkdirs();
		} else {
			if (f.isFile()) {
				throw new IOException("路径是一个文件，不能创建为目录：" + dirPath);
			}
		}
		return ret;
	}

	/**
	 * 获取文件扩展名
	 * 
	 * @param fileName
	 * @return
	 */
	public static String getFileExtension(String fileName) {
		if (fileName == null || "".equals(fileName.trim()) || fileName.indexOf(".") == -1) {
			return "";
		}
		return fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).trim();
	}

	/**
	 * 根据指定的路径，获取该路径下的所有指定文件的路径
	 * 
	 * @param strPath
	 *            目录路径
	 * @param resultList
	 *            返回的结果集，递归调用
	 * @param filter
	 *            文件过滤器
	 * @throws RuntimeException
	 */
	public static List<String> refreshFileList(String strPath, List<String> resultList, FileFilter filter) throws Exception {
		File dir = new File(strPath);
		if (!dir.isDirectory()) {
			throw new RuntimeException("The parameters \"" + strPath + "\" is not a valid directory path.");
		}
		if (resultList == null) {
			resultList = new ArrayList<String>();
		}
		File[] files = dir.listFiles(filter);
		if (null != files) {
			for (File f : files) {
				if (f.isDirectory()) {
					refreshFileList(f.getAbsolutePath(), resultList, filter);
				} else {
					resultList.add(f.getAbsolutePath());
				}
			}
		}
		return resultList;
	}

	/**
	 * 
	 * sourceFile:源文件的路径 targetDirectory:保存文件的目录(例:'C:\\') prefix:是分割后文件的前缀(例:'2015-09-09') delimiter 定界符（如：'_'） size:是分隔后单一文件的大小单位是2kb的倍数,size传10，分割后单一文件就是20K。传5120，文件就是10M一个。
	 * 
	 **/
	public static List<String> cutToMoreFile(String sourceFile, String targetDirectory, String prefix, String delimiter, int size) throws IOException {
		// 一般传过来的文件名带有后缀， 这里要去掉，最后会统一加上后缀名：".TXT"
		String suffix = ".txt";
		int separator = prefix.lastIndexOf(".");
		if (separator > -1) {
			suffix = prefix.substring(separator);
			prefix = prefix.substring(0, separator);
		}
		List<String> cutFileList = new ArrayList<String>();
		// 加载源文件
		File source = new File(sourceFile);
		InputStream in = null;
		OutputStream out = null;
		int len = 0;
		int fileIndex = 1;
		// 设置一次加载的大小
		byte[] buffer = new byte[2048];
		try {
			// 把源文件读到InputStream中
			in = new FileInputStream(source);
			// 循环
			while (true) {
				// 分割后的文件流(例如文件EXP20050811.txt，该文件大于十兆需要拆分，
				// 拆分后文件命名应该为EXP20050811_1.txt、EXP20050811_2.txt、EXP20050811_3.txt......)
				String destinationFile = targetDirectory + File.separator + prefix + delimiter + String.format("%05d", fileIndex++) + suffix;
				cutFileList.add(destinationFile);
				// 这里需要注意下，因为每次将out变量指向新的输出流(FileOutputStream)时，最后在finally中只会关掉最后一个分割文件的输出流，
				// 所以前面所有new出来的输出流都没关闭，会导致后bug出现。故在每次new下一个输出流对象时，必须关闭当前输出流再new下一个
				IOUtils.closeQuietly(out);
				out = new FileOutputStream(destinationFile);
				for (int i = 0; i < size; i++) {
					// 如果文件读取完就退回方法。
					if ((len = in.read(buffer)) != -1) {
						// 写入分割后的文件
						out.write(buffer, 0, len);
					} else {
						// 执行finally内容后,退出方法
						return cutFileList;
					}
				}
			}
		} catch (IOException e) {
			logger.error("error", e);
		} finally {
			IOUtils.closeQuietly(in);
			IOUtils.closeQuietly(out);
		}

		return cutFileList;
	}

	/**
	 * 判断文件的编码格式
	 * 
	 * @param fileName
	 * @return
	 * @throws Exception
	 */
	public static String codeString(String fileName) throws Exception {
		String code = null;
		try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(fileName))) {
			int p = (bin.read() << 8) + bin.read();
			switch (p) {
			case 0xefbb:
				code = "UTF-8";
				break;
			case 0xfffe:
				code = "Unicode";
				break;
			case 0xfeff:
				code = "UTF-16BE";
				break;
			default:
				code = "GBK";
			}
		}
		return code;
	}

	/**
	 * 递归删除指定目录下的所有文件及子目录下所有文件
	 * 
	 * @param dir
	 *            指定删除目录
	 * @return
	 */
	public static boolean deleteDir(File dir) {
		if (dir.isDirectory()) {
			File[] listFiles = dir.listFiles();
			for (int i = 0; i < listFiles.length; i++) {
				boolean success = deleteDir(listFiles[i]);
				if (!success) {
					return false;
				}
			}
		}
		// 目录此时为空，可以删除
		return dir.delete();
	}

	public static void main(String[] args)  {
		File dir = new File("C:\\Users\\TaoPingPing\\Desktop\\附件四：模板2015-08-06\\1");
		// FileUtil.deleteDir(dir);
		// System.out.println("临时文件夹删除");
		// File dir = new File(localTmpDir);
		File[] listFiles = dir.listFiles();
		for (File file : listFiles) {
			try {
				boolean b = file.delete();
				System.out.println(b);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println("临时文件夹删除");
		// String fileName = "C:\\tpp\\收单规则表用法.txt";
		// String strTmp = "";
		// StringBuffer sBuffer = new StringBuffer();
		// System.out.println(codeString(fileName));
		// try(BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), codeString(fileName)))){
		// while((strTmp = in.readLine())!=null){
		// sBuffer.append(strTmp);
		// }
		// System.out.println(sBuffer.toString());
		// }
		// List<String> list = cutToMoreFile("E:\\Documents\\work\\上海_全量集团客户信息数据\\111\\ziguanhuadanshanghai20160816.txt", "E:\\Documents\\work\\上海_全量集团客户信息数据\\111", "ziguanhuadanshanghai20160816.txt",
		// "", 7680);
		// for(String name : list){
		// System.out.println(name);
		//
		// }
	}

}
